頁面切換動畫最常使用的模式有
1.Hero動畫:使兩個頁面之間的共享widgets平滑切換的方式
2.自訂義轉場動畫:如果不滿意預設的轉場效果。可以使用PageRouteBuilder
,自訂義轉場動畫
我們會先創建兩個頁面並寫入調轉頁面的觸發動作
創建第一頁
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('頁面跳轉動畫page1'),
),
body: GestureDetector(
child: Hero(
tag: 'First photo', // Hero動畫的標籤,兩個頁面共享相同的標籤
child: Image.network('https://stickershop.line-scdn.net/stickershop/v1/product/1427855/LINEStorePC/main.png?v=1'),
),
//點擊圖片觸發跳轉下頁的指令
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => SecondPage(),
));
},
),
);
}
}
創建第二頁
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('頁面跳轉動畫page2'),
),
body: GestureDetector(
child: Hero(
tag: 'Second photo', // 與第一頁相同的Hero標籤
child: Image.network('https://img.lovepik.com/free-png/20210919/lovepik-goodbye-and-bye-bye-to-cartoon-facial-pack-png-image_400963701_wh1200.png'),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => FirstPage(), // 點擊圖片返回第一頁
));
},
),
);
}
}
如果想要自訂義轉場動畫的時候,就要用到PageRouteBuilder
的方法了!
這便是設定成平移動畫切換
這邊簡單更改上面程式碼中onTap: ()
的部分
onTap: () {
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) {
return FirstPage(); // 返回第一頁
},
//自定義頁面切換時的動畫效果
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(-1.0, 0.0); // 起始位置
const end = Offset.zero; // 終點位置
const curve = Curves.ease; // 動畫曲线
// 創建一個tween,定義起始和終點位置
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
//將tween應用到animation對象上,獲得一個位移動畫
var offsetAnimation = animation.drive(tween);
return SlideTransition(
position: offsetAnimation, // 使用平移动画
child: child,
);
},
));
},
並在main方法中設定應用程式主題為自定義的頁面切換動畫主題
void main() {
runApp(MaterialApp(
home: FirstPage(),
theme: ThemeData(
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.android: OpenUpwardsPageTransitionsBuilder(),
},
),
),
));
}
完整程式碼
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: FirstPage(),
theme: ThemeData(
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.android: OpenUpwardsPageTransitionsBuilder(),
},
),
),
));
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('頁面跳轉動畫page1'),
),
body: GestureDetector(
child: Hero(
tag: 'First photo',
child: Image.network(
'https://stickershop.line-scdn.net/stickershop/v1/product/1427855/LINEStorePC/main.png?v=1'),
),
onTap: () {
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) {
return SecondPage();
},
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(1.0, 0.0);
const end = Offset.zero;
const curve = Curves.ease;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
var offsetAnimation = animation.drive(tween);
return SlideTransition(
position: offsetAnimation,
child: child,
);
},
));
},
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('頁面跳轉動畫page2'),
),
body: GestureDetector(
child: Hero(
tag: 'Second photo',
child: Image.network(
'https://img.lovepik.com/free-png/20210919/lovepik-goodbye-and-bye-bye-to-cartoon-facial-pack-png-image_400963701_wh1200.png'),
),
onTap: () {
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) {
return FirstPage(); // 返回第一頁
},
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(-1.0, 0.0);
const end = Offset.zero;
const curve = Curves.ease;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
var offsetAnimation = animation.drive(tween);
return SlideTransition(
position: offsetAnimation,
child: child,
);
},
));
},
),
);
}
}
成果展示
https://imgur.com/a/9ts9F4E